/**
 * 
 */
package org.extdev.protocol.unsigned;

/**
 * @author LAP
 *
 */
public class UnsignedByte {
	
	private static final byte BYTE_SIGN_CEEPER = 0x40;
	private static final byte BYTE_SIGN_POSITION = 7;
	private static final byte BYTE_MAX_BIT_NO = 7;
	private static final byte BYTE_MIN_BIT_NO = 0;
	private static final byte RIGHT_BIT_NUMBER = 1;
	
	private byte data;
	/**
	 * Constructor sets data to 0
	 */
	public UnsignedByte() {
		this((byte) 0);
	}
	
	public UnsignedByte(byte data) {
		setByte(data);
	}
	
	public boolean isSigned() {
		return getBitValue(BYTE_SIGN_POSITION);
	}
	
	public byte getByte() {
		return data;
	}
	
	public UnsignedByte setByte(byte data) {
		this.data = data;
		return this;
	}
	
	/**
	 * @param position - position of bit in range between 0 and 7
	 * @return boolean value of bit
	 * @throws IllegalArgumentException
	 */
	public boolean getBitValue(int position) {
		if(position > BYTE_MAX_BIT_NO || position < BYTE_MIN_BIT_NO) 
			throw new IllegalArgumentException("Position must be in byte range");
		byte b = (byte) (1 << position);
		return (data & b) == b;
	}
	
	public UnsignedByte rotateRight(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			for(int i = 0; i < count; i++) {
				boolean isLastBit = getBitValue(0);
				unsignedRightShift(1);
				if(isLastBit) {
					data |= Byte.MIN_VALUE;
				}
			}
		}
		return this; 
	}
	
	public UnsignedByte rotateLeft(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			for(int i = 0; i < count; i++) {
				boolean isSigned = getBitValue(BYTE_SIGN_POSITION);
				leftShift(1);
				if(isSigned) {
					data |= RIGHT_BIT_NUMBER;
				}
			}
		}
		return this;
	}
	
	public UnsignedByte unsignedRightShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			boolean sign = getBitValue(BYTE_SIGN_POSITION);
			byte signCeeper = 0;
			if(sign) {
				data &= 0x7f;
				signCeeper = (byte) (BYTE_SIGN_CEEPER >>> (count - 1));
			}
			data >>>= count;
			data |= signCeeper;
		}
		return this;
	}
	
	public UnsignedByte leftShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			data <<= count;
		}
		return this;
	}
	
	public UnsignedByte rightShift(int count) {
		if(count < 0) throw new IllegalArgumentException("count must be above 0");
		if(count > 0) {
			data >>= count;
		}
		return this;
	}

	public UnsignedByte xor(byte b) {
		data ^= b;
		return this;
	}
	
	public UnsignedByte or(byte b) {
		data |= b;
		return this;
	}
	
	public UnsignedByte and(byte b) {
		data &= b;
		return this;
	}
}
